#ifndef NANE_SUBSYSTEMPRODUCT_H
#   define  NANE_SUBSYSTEMPRODUCT_H

#   include "nane/core/assert.h"
#   include "nane/core/IBase.h"
#   include "nane/core/IntrusivePtr.h"

namespace nane
{

    class SubSystemProduct
    {
    public:
        class Implementation
            : public IRefCounted
        {
        };

    public:
        SubSystemProduct( const NullType& = NullPtr )
            : m( NULL )
        {
        }

        SubSystemProduct( Implementation* _impl )
            : m( _impl )
        {
            if( m != NULL )
            {
                m->Ref();
            }
        }

        SubSystemProduct( const SubSystemProduct& _other )
            : m( _other.m )
        {
            if( m != NULL )
            {
                m->Ref();
            }
        }

        ~SubSystemProduct()
        {
            if( m != NULL
                    && m->Unref() == 0 )
            {
                m->Dispose();
            }
        }

        void Swap( SubSystemProduct& _other )
        {
            Implementation* obj = _other.m;
            _other.m = m;
            m = obj;
        }

        SubSystemProduct& operator=( const SubSystemProduct& _rhs )
        {
            SubSystemProduct(_rhs).Swap(*this);
            return *this;
        }

        SubSystemProduct& operator=( const NullType& )
        {
            SubSystemProduct(NULL).Swap(*this);
            return *this;
        }

//        bool operator==( const NullType& ) const
//        {
//            return m == NULL;
//        }

//        bool operator!=( const NullType& ) const
//        {
//            return m != NULL;
//        }

        bool operator==( const SubSystemProduct& _rhs )
        {
            return m == _rhs.m;
        }

        bool operator!=( const SubSystemProduct& _rhs )
        {
            return m != _rhs.m;
        }

    protected:
        Implementation* m;
    };

    template<class Creator, class Interface, class RefBase = SubSystemProduct::Implementation>
    class SubSystemProductImplBase
        : public RefCounted<RefBase>
    {
    public:
        SubSystemProductImplBase( Creator* _creator, Interface _interface )
            : creator( _creator )
            , interface( _interface )
        {
            NANE_ASSERT( creator != NULL, "Creator must be valid" );
        }

        ~SubSystemProductImplBase()
        {
        }

    public:
        Creator* creator;
        Interface interface;
    };

    template<class Impl, class Base>
    class Disposable
        : public Base
    {
    public:
        Disposable()
            : Base()
        {
        }

        template<typename P1>
        Disposable( P1 _p1 )
            : Base( _p1 )
        {
        }

        template<typename P1, typename P2>
        Disposable( P1 _p1, P2 _p2 )
            : Base( _p1, _p2 )
        {
        }

        template<typename P1, typename P2, typename P3>
        Disposable( P1 _p1, P2 _p2, P3 _p3 )
            : Base( _p1, _p2, _p3 )
        {
        }

        template<typename P1, typename P2, typename P3, typename P4>
        Disposable( P1 _p1, P2 _p2, P3 _p3, P4 _p4 )
            : Base( _p1, _p2, _p3, _p4 )
        {
        }


    private:
        void Dispose()
        {
            Base::creator->Release(static_cast<Impl*>(this));
        }
    };

    template<class Impl, class Creator, class Interface, class Base = SubSystemProductImplBase<Creator, Interface> >
    class SubSystemProductImpl
        : public Disposable<Impl, Base>
    {
    public:
        SubSystemProductImpl( Creator* _creator, Interface _interface )
            : Disposable<Impl, Base>( _creator, _interface )
        {
        }

        ~SubSystemProductImpl()
        {
        }
    };
    
}   // namespace nane

#endif  // NANE_SUBSYSTEMPRODUCT_H
